#include "fxcc/core/graph/opengl3/ImGuiGlfwApp.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "fxcc/imgui/Editor.h"



#include "fxcc/core/AssertManager.h"

using namespace fxcc::platform;
using namespace fxcc::graph::common;
using namespace fxcc::graph::opengl3;
using namespace fxcc::imgui::graph::opengl3;
using BaseApp = fxcc::imgui::graph::opengl3::GlfwApp;

#undef main

struct SimpleApp : public BaseApp
{
public:

    std::shared_ptr<ImageMipmap> m_ImageMipMap;

    std::shared_ptr<fxcc::graph::opengl3::Texture2DJack> m_Texture2DJack;

    std::shared_ptr<fxcc::graph::opengl3::MeshJack> m_CubeMesh, m_QuadMesh;

    std::shared_ptr<fxcc::graph::opengl3::Effect3d> m_Effect;

    std::shared_ptr<fxcc::graph::opengl3::Effect3d> m_ArrayEffect;

    std::shared_ptr<fxcc::graph::opengl3::RenderTargetJack> m_RTJack;

    std::shared_ptr<fxcc::graph::opengl3::Texture2DArrayJack> m_TexArray;

    std::shared_ptr<fxcc::graph::opengl3::Texture3DJack> m_Texture3D;

    glm::vec4 color;

    fxcc::graph::common::Camera camera;

    int index = 0;

    fxcc::graph::common::Transform transform;

    SimpleApp(const fxcc::platform::common::App::Desc &desc) : BaseApp(desc), color(1.0)
    {
    }
    bool Init() override
    {
        if (!BaseApp::Init())
        {
            return false;
        }

        if (!InitResources())
        {
            return false;
        }

        return true;
    };

    void printOpenGLESVersion()
    {
        const char *version = (const char *)glGetString(GL_VERSION);
        std::cout << "OpenGL ES Version: " << version << std::endl;
    };

    int useArray{ 0 };

    bool InitResources()
    {
        camera.SetPosition(glm::vec3(5.0f));
        camera.LookAt(glm::vec3(0.0f));

        auto& am = fxcc::AssertManager::Inst();

        ImageMipmap::Desc desc;
        desc.m_wicPath = am.GetFile("container.jpg");
        desc.m_wicReq = 0;
        desc.m_wicHdr = false;
       
        //auto& rs = fxcc::graph::common::Resources::Inst();
        m_ImageMipMap = std::make_shared<ImageMipmap>(desc);

        fxcc::graph::opengl3::Texture2DJack::Desc jackDesc;
        jackDesc.m_WICConfig = desc;
        jackDesc.m_DDSPath = am.GetFile("Model/Sponza/sponza_fabric_blue_diff.dds");
        jackDesc.m_Type = fxcc::graph::opengl3::Texture2DJack::Desc::_WIC_;

        jackDesc.m_SampleType = fxcc::graph::common::SamplerType::_sampler_2d_default_;

        //while (1)
        m_Texture2DJack = std::make_shared< fxcc::graph::opengl3::Texture2DJack>(jackDesc);

        m_CubeMesh = std::make_shared<fxcc::graph::opengl3::MeshJack>(Geometry::CreateBox());
        m_QuadMesh = std::make_shared<fxcc::graph::opengl3::MeshJack>(Geometry::CreateQuad());


        {
            fxcc::graph::opengl3::Texture2DArrayJack::Desc desc1;
            desc1.SetDDSPath(fxcc::AssertManager::GetRelativeFile("Texture/output/array.dds"));

            m_TexArray = std::make_shared<fxcc::graph::opengl3::Texture2DArrayJack>(desc1);

        }
        {
            fxcc::graph::opengl3::Texture3DJack::Desc desc1;
            desc1.SetDDS(fxcc::AssertManager::GetRelativeFile("Texture/output/volume.dds"));
            m_Texture3D = std::make_shared<fxcc::graph::opengl3::Texture3DJack>(desc1);


        }
        {
            const std::string fragCode = R"(

out vec4 FragColor;

uniform sampler2D diffuse;

void main()
{
    vec4 diffuseColor = texture(diffuse, TexCoord);
    FragColor = diffuseColor ;  
}
)";
            m_Effect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);

        }
        {
            const std::string fragCode = R"(

out vec4 FragColor;

uniform sampler2DArray diffuse;
uniform sampler3D volume;

uniform int index;
uniform float axis;

uniform int useArray;

void main()
{
    if(useArray!=0)
    {
        FragColor = texture(volume, vec3(TexCoord, float(axis)));
    }else
    {
        FragColor = texture(diffuse, vec3(TexCoord, float(index)));
    }

}
)";

            m_ArrayEffect = std::make_shared<fxcc::graph::opengl3::Effect3d>(fragCode);
        }
        return true;
    };

    fxcc::imgui::Editor editor;

    void OnEdit() override
    {
        ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
        ImGui::Begin("Basic");
        editor.EditInst<ImageMipmap>("image", *m_ImageMipMap);
        ImGui::End();

        ImGui::Begin("Texture");
        editor.EditInst<fxcc::graph::common::Texture2DJack>("texture", *m_Texture2DJack);
        ImGui::End();

        ImGui::Begin("TextureArray");
        editor.CheckBoxInst<int>("useArray", useArray);
        ImGui::DragInt("index", &index, 1.0f, 0, 5);
        ImGui::End();


        ImGui::Begin("Framebuffer");
        editor.AddFrameBuffer(m_RTJack->m_Textures[0]->GetTextureId());
        ImGui::End();
    }
    void OnDestroy() override
    {
      
        BaseApp::OnDestroy();
    }
    void OnFrameRender() override
    {
        glViewport(0, 0, m_Desc.m_Size.x, m_Desc.m_Size.y);

        glClearColor(color.x, color.y, color.z, color.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_RTJack->Begin();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_ArrayEffect->Begin();
        m_ArrayEffect->SetCamera(camera);
        
        m_ArrayEffect->m_Shader->Use();
        m_ArrayEffect->m_Shader->setInt("useArray", useArray);
        m_ArrayEffect->m_Shader->setInt("index", index);
        m_ArrayEffect->m_Shader->setFloat("axis", (float)index / (float)5.f);
        m_ArrayEffect->m_Shader->setInt("diffuse", 0);
        m_ArrayEffect->m_Shader->setInt("volume", 1);
        m_TexArray->Active(0);
        m_Texture3D->Active(1);
        
        m_ArrayEffect->SetObjData(transform);
        m_ArrayEffect->InstMeshJack(m_CubeMesh.get());
        m_ArrayEffect->End();

        m_RTJack->End();
    };

    void OnFramebuffersize(int w, int h) override
    {
        BaseApp::OnFramebuffersize(w, h);
        camera.SetAspect(m_Desc.Aspect());

        ImageMipmap::MipMapData image(w, h, 4, 0);
        fxcc::graph::opengl3::RenderTargetJack::Desc desc(1, image);

        m_RTJack = std::make_shared<fxcc::graph::opengl3::RenderTargetJack>(desc);

    }
    void OnUpdate() override
    {
        BaseApp::OnUpdate();

        float ctTime = m_GlfwlTimer.m_CurrentTime;
        camera.FreeMove(m_Input, m_GlfwlTimer.m_DeltaTime);

        float deltaTime = m_GlfwlTimer.m_DeltaTime;


    }
};

int main()
{
    ztclog::pushFunction([](const ztclog::Line &line)
                         {
		if (line.m_Type != ztclog::Line::Type::_line_debug_)
		{
			std::cout << line.m_Text << std::endl;
		} });

    using _App = SimpleApp;
    using _Desc = fxcc::platform::common::App::Desc;

    _Desc desc;
    desc.m_Pos = glm::ivec2(100, 100);
    desc.m_Size = glm::ivec2(900, 600);
    desc.m_ScaleFactor = 1.0f;

    desc.m_Title = "jack data";
    std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
    return _app->Run();
};
